package com.myebills.ebpsfrontend.cust.controller;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException;
import java.util.StringTokenizer;
import java.util.Vector;

import com.checkfree.isolutions.customer.persist.*;
import com.checkfree.isolutions.admin.ObjectId;
import com.checkfree.isolutions.statement.persist.Statement;
import com.checkfree.isolutions.customer.persist.User;
import com.checkfree.isolutions.customer.persist.UserHomeImpl;
import com.checkfree.isolutions.customer.persist.Merchant;
import com.checkfree.isolutions.customer.persist.MerchantHomeImpl;
import com.checkfree.isolutions.utility.CFiError;
import com.checkfree.isolutions.property.Properties;
import com.checkfree.isolutions.property.PropertiesConfig;
import com.ibm.logging.ILogger;
import com.ibm.logging.IRecordType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.checkfree.isolutions.security.Cipher;

/**
 * Derive from this class to create a Logon servlet when no session exists.
 * Instance of Template pattern (GOF).
 * Override, doPreTransaction(), authenticateUser(), and doPostTransaction().
 */
public class EbppxCusEbdLogonServlet extends EbppxServlet {

    //possible logon messages
    private static String MSG_SESSION_EXPIRED ="Your session timed out or is invalid";
    private static String MSG_AUTHENTICATION_FAIL ="EBPS Authentication Failure";
    private static String MSG_INVALID_USER ="Invalid User";
    private static String MSG_INVALID_EMAIL ="Invalid User Email";
    private static String MSG_INVALID_ACCOUNT_NO ="Invalid Account Number";
    private static String MSG_INTERNAL_ERROR ="Internal Error";


    //Delimiter for the message to get all the tokens
    private static String STR_DELIMITER=",";

    /**
     * Override to perform actions after transaction is completed or rolled back by goSession().
     * When overriding, the convention will be to call super.doPostTransaction()
     * <b>after</b> invoking any other operations that may affect state of servlet.
     */
    protected void doPostTransaction(
    HttpServletRequest req,
    HttpServletResponse res
    ) throws IOException, ServletException {}

    /**
     * Override to perform actions before transaction is completed or rolled back by goSession().
     * When overriding, the convention will be to call super.doPostTransaction()
     * <b>before</b> invoking any other operations that may affect state of servlet.
     */
    protected void doPreTransaction(
    HttpServletRequest req,
    HttpServletResponse res
    ) throws IOException, ServletException {}

    protected class LogonException extends Exception {
        public LogonException(String s) {
            super(s);
        }
    }

    /**
     * Perform decryption for the parameter and some simple validation to the data
     *
     * @param strTimestamp - the timestamp in yyyymmddhhMMss format
     * @param strEncParam - the encrypted parameter containing the detail information
     *
     * @return the object representing the logon user
     * @exception LogonException logon failed
     */
    protected EbppxEcsUser parseParam(HttpServletRequest req)
    throws EbppxCusEbdLogonServlet.LogonException, javax.servlet.ServletException {
        final String fName = "parseParam";

        ILogger trcLogger = getTraceLogger(req);

        if (trcLogger.isLogging())
            trcLogger.entry(IRecordType.TYPE_INFO, this, fName);

        //get the timestamp and encrypted value from ECS

        String strEncParam = EbppxUtil.nullToEmpty(
        req.getParameter(getContextInitParameter(EbppxConstants.ECS_ENCRYPT_PARAM_NAME,"param"))
        );


        //Decryption
        String  clearText= null;

        try {


			com.checkfree.isolutions.property.Properties appCfg = com.checkfree.isolutions.property.PropertiesConfig.getApplicationSettings();
			boolean ecsEncryptionOn = false;

			if (appCfg.hasProperty("EcsEncryption") == false)
				ecsEncryptionOn = false;
			else {
				String temp = appCfg.getProperty("EcsEncryption");
				if (temp.compareToIgnoreCase("Yes")==0){
					ecsEncryptionOn = true;
				}
			}

			if (ecsEncryptionOn){
				//EbppxTransformer transform = new EbppxTransformer();
				/*clearText = Cipher.decryptToString(
				getContextInitParameter(EbppxConstants.ECS_AUTHENTICATION_ALGO,"3DES/PCBC/PKCS5"),
				strTimestamp+getContextInitParameter(EbppxConstants.ECS_HARD_KEY,strTimestamp),
				strEncParam, 0 );*/
				clearText = EncryptionHelper.decrypt(strEncParam,getContextInitParameter(EbppxConstants.ECS_HARD_KEY,""));
			} else {
				clearText = strEncParam;
			}


            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_INFO, this, fName,"decrypted parameter="+clearText);

        }
        catch (CFiError cfie) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"CFiError="+cfie);

            throw new LogonException(MSG_AUTHENTICATION_FAIL);
        }


        //Split the decypted text into user Id, email and account numbers
        EbppxEcsUser ecsu = new EbppxEcsUser();


        // Get Merchant Name
        String merchantName = "";
        try {
            com.checkfree.isolutions.property.Properties appCfg = com.checkfree.isolutions.property.PropertiesConfig.getApplicationSettings();

            if (appCfg.hasProperty("MerchantName")){
                merchantName = appCfg.getProperty("MerchantName");
                ecsu.setMerchantName(merchantName);
                if (trcLogger.isLogging())
                    trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"Merchant name found : "+merchantName);
            }
        }
        catch (CFiError cfi) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"Error finding merchant : "+cfi);
        }

        StringTokenizer strTok = new StringTokenizer(clearText, STR_DELIMITER);
        int totalToken = strTok.countTokens();

        if (totalToken < 3 || totalToken > 7) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_INFO, this, fName,"incorrect total token :"+totalToken);

            throw new LogonException(MSG_AUTHENTICATION_FAIL);
        }

        ecsu.setUserId(strTok.nextToken());
        ecsu.setEmail(strTok.nextToken());

        try{

    	    while (strTok.hasMoreTokens()) {
				// Added by Meau
				String strToken = strTok.nextToken();

				// used to check the dot(.) to see if it is an old or new account no
				if(strToken.indexOf(".")>0){// if there is a dot
					StringTokenizer stknz = new StringTokenizer(strToken,".");
					String strNo = "";
					String strRemainder = "";
					int intNo = 0;
					if(stknz.hasMoreTokens()){
						strNo = stknz.nextToken();
						strRemainder = stknz.nextToken();

						intNo = Integer.parseInt(strNo);
						if(intNo>=7 || intNo==1){// bigger or equals than 8,new account no,then remove the dot
							strToken = EbppxUtil.removeChar(strToken, '.');
						}
					}
				}
				String strAcctId = AcctDetails.getAcctId(strToken);
				String strOldAccountKey = AcctDetails.getOldAccountKey(strAcctId);

				if(strAcctId==null || strAcctId.equals("")){// doesn't exist in account details table
					if(strToken.indexOf(".")>0){//strToken is an old account no
						//old account no and doesnt exist in account details
						ecsu.setAccount(strToken);
					}else{// new account no

						// used to check if exist in checkfree account table
		                Merchant cfiMerchant = MerchantHomeImpl.singleton().findByName(merchantName);
		                Account account = AccountHomeImpl.singleton().findByExternalKeyAndMerchant(strToken, cfiMerchant);

		                if(account!=null){//account is already loaded into checkfree database
							// insert into accountdetails
							AcctDetails.insertAcctDetails(strToken,"","","");
							// set the account in ecs user
							ecsu.setAccount(strToken);
						}else{
							// new but invalid account no(doesn't exist in check free account table)
							ecsu.setAccount(strToken);
						}
					}

				}else{// exist in account details table
					ecsu.setAccount(strAcctId);
				}
				ecsu.setOldAccount(strOldAccountKey);
			}
		}
		catch( Throwable t){
			throw new ServletException(t.toString(), t);
		}

        if (trcLogger.isLogging()) {
            StringBuffer info = new StringBuffer();
            info.append("user Id=").append(ecsu.getUserId()).append(", email=").append(ecsu.getEmail());
            info.append(", TotalAccounts=").append(ecsu.getTotalAccounts()).append(", Accounts=");

            for (int i=0; i<ecsu.getTotalAccounts() ;i++ ) {
                info.append(ecsu.getAccount(i)).append("|");
            }

            trcLogger.text(IRecordType.TYPE_INFO, this, fName, info.toString());
        }

        //Some validation wouldn't hurt
        if ( !EbppxValidation.isValidString(ecsu.getUserId(), EbppxValidation.CHARACTER,
        false, -1,-1) ) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"invalid user id :"+ecsu.getUserId());

            throw new LogonException(MSG_INVALID_USER);
        }
        else if ( !EbppxValidation.isValidEmail(ecsu.getEmail(), true) ) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"invalid email :"+ecsu.getEmail());

            throw new LogonException(MSG_INVALID_EMAIL);
        }

        for (int i=0; i<ecsu.getTotalAccounts() ;i++ ) {
            if ( !EbppxValidation.isValidString(ecsu.getAccount(i), EbppxValidation.INTEGER+".-",
            false, -1,-1) ) {
                if (trcLogger.isLogging())
                    trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"invalid account number :" + ecsu.getAccount(i));

                throw new LogonException(MSG_INVALID_ACCOUNT_NO);
            }
        }

        if (trcLogger.isLogging())
            trcLogger.exit(IRecordType.TYPE_INFO, this, fName);

        return ecsu;
    }


    /**
     * Attempt to validate logon
     * using i-Series User authentication.
     * Upon success, return user object.
     *
     * @param ecsu - the EcsUser object
     * @return the CFI User
     *
     * @exception LogonException logon failed
     */
    protected User authenticateUser(EbppxEcsUser ecsu, HttpServletRequest req)
    throws EbppxCusEbdLogonServlet.LogonException, javax.servlet.ServletException {
        final String fName = "authenticateUser";
        ILogger trcLogger = getTraceLogger(req);

        if (trcLogger.isLogging())
            trcLogger.entry(IRecordType.TYPE_INFO, this, fName);

        // Make sure the merchant is in the DB.


        if (trcLogger.isLogging())
            trcLogger.text(IRecordType.TYPE_INFO, this, fName,"Merchant : "+ecsu.getMerchantName());

        Merchant cfiMerchant = null;
        try {
            cfiMerchant = MerchantHomeImpl.singleton().findByName(ecsu.getMerchantName());
        }
        catch (Throwable e) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"Error finding merchant : "+e);

            throw new LogonException(MSG_INTERNAL_ERROR);
        }

        if (cfiMerchant == null) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"Error finding merchant : null");

            throw new LogonException(MSG_INTERNAL_ERROR);
        }

        // Make sure the user is in the DB.
        User cfiUser = null;

        try {
            cfiUser = getUserHome().findByLogonIdAndMerchant(ecsu.getUserId(),cfiMerchant);

            //Create a new user if not found
            if (cfiUser ==null) {
                if (trcLogger.isLogging())
                    trcLogger.text(IRecordType.TYPE_INFO, this, fName,"User not found, creating user : "+ecsu.getUserId());

                try {
                    cfiUser = getUserHome().create(ecsu.getUserId(),cfiMerchant);
                }
                catch (Exception exc) {
                    if (trcLogger.isLogging())
                        trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"Error creating new user : "+exc);

                    throw new LogonException(MSG_INTERNAL_ERROR);
                }
            }
        }
        catch (Throwable t) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"Error finding user : "+t);

            throw new LogonException(MSG_INTERNAL_ERROR);
        }

        if (cfiUser == null) {
            if (trcLogger.isLogging())
                trcLogger.text(IRecordType.TYPE_ERROR, this, fName,"Error getting user : null");

            throw new LogonException(MSG_INVALID_USER);
        }

        if (trcLogger.isLogging())
            trcLogger.exit(IRecordType.TYPE_INFO, this, fName);

        return cfiUser;
    }

    /**
     * Connect to i-Series database and begin transaction,
     * and call abstract method <i>authenticateUser<i> to authenticate user.
     * If user is authenticated, redirect browser to URL named by ConstantsURL_LOGON_SUCCESS_PARAM.
     * Otherwise, redirect browser to URL named by Constants.URL_LOGON_FAILURE_PARAM.
     * These may be either request, servlet, or context parameters.
     */
    protected final void doRequest(
    HttpServletRequest req,
    HttpServletResponse res
    ) throws ServletException, java.io.IOException {
        final String fName = "doRequest";
        ILogger trcLogger = getTraceLogger(req);

        if (trcLogger.isLogging())
            trcLogger.entry(IRecordType.TYPE_INFO, this, fName);


        //Begin transaction
        activateISeriesEngine(req, fName);

        try {
            doPreTransaction(req, res);
            beginTransaction(req, fName);

            try {

                req.setAttribute("_cache_refresh", "true");
                final EbppxEcsUser ecsu = parseParam(req);
                final User cfiUser = authenticateUser(ecsu, req);
                // 0 for disabled, 1 for enabled
                String strEnableButton = "1";

                // if a session doesn't exist, sessionPrev is null
                final HttpSession sessionPrev = req.getSession(false);

                if (null != sessionPrev) {
                    try {
                        sessionPrev.invalidate();
                    } catch (IllegalStateException e) {
                        // Do nothing (session was already invalidated).
                    }
                }

                // create a new session, if one doesn't already exist.
                final HttpSession session = req.getSession(true);

                // Added by Meau for disabling the buttons for corporate customer
                final Vector cfiAccounts = ecsu.getAccounts();
            	final int size = cfiAccounts.size();
            	for(int i=0;i<size;i++){
            	    final Account cfiAccount = (Account) cfiAccounts.elementAt(i);
            	    final String strAcctExtKey = AcctDetails.getAcctId(cfiAccount.getExternalKey());
            	    if(strEnableButton.equals("1")){
	                	if(AcctDetails.getCorpCust(strAcctExtKey)!=null){
		            	    if(AcctDetails.getCorpCust(strAcctExtKey).equals("1") || AcctDetails.getCorpCust(strAcctExtKey).equals("2") || AcctDetails.getCorpCust(strAcctExtKey).equals("3")){
								strEnableButton = "0";
							}
						}
					}
				}

				// end added by Meau

                // place User object in session
                //session.setAttribute(EbppxConstants.CFI_USER, cfiUser);
                session.setAttribute(EbppxConstants.ECS_USER, ecsu);
                session.setAttribute(EbppxConstants.USER_LOGGED_ON,"true");
                session.setAttribute(EbppxConstants.BUTTON_ENABLED,strEnableButton);

			System.out.println("SUBMIT LOGON SERVLET END&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");

                //redirect to next page
                redirectToMappedUrl(
                req,
                res,
                EbppxConstants.URL_LOGON_SUCCESS_PARAM,
                "");

            }
            catch (LogonException ex) {
                redirectToMappedUrl(
                req,
                res,
                EbppxConstants.URL_LOGON_FAILURE_PARAM,
                EbppxConstants.MESSAGE_0 + "=" + java.net.URLEncoder.encode(ex.getMessage()));
            }

            commitTransaction(req, fName);
            doPostTransaction(req, res);
        }
        catch (Throwable t) {
            throw new ServletException(t.toString(), t);
        }
        finally {
            rollbackTransaction(req, fName);
            deactivateISeriesEngine(req, fName);
        }

        if (trcLogger.isLogging())
            trcLogger.exit(IRecordType.TYPE_INFO, this, fName);
    }
}
